package com.xjh.basestudy.javabase.thread_final.threadlocal.demo;

/**
 * @Author:XuJianHua
 * @Date:2022/10/27
 * @Description:
 * 每个线程内需要保存类似于全局变量的信息（例如在拦截器中获取的用户信息），可以让不同方法直接使用，避免参数传递的麻烦却不想被多线程共享（因为不同线程获取到的用户信息不一样）。
 *
 * 例如，用 ThreadLocal 保存一些业务内容（用户权限信息、从用户系统获取到的用户名、用户ID 等），这些信息在同一个线程内相同，但是不同的线程使用的业务内容是不相同的。
 *
 * 在线程生命周期内，都通过这个静态 ThreadLocal 实例的 get() 方法取得自己 set 过的那个对象，避免了将这个对象（如 user 对象）作为参数传递的麻烦。
 *
 * 比如说我们是一个用户系统，那么当一个请求进来的时候，一个线程会负责执行这个请求，然后这个请求就会依次调用service-1()、service-2()、service-3()、service-4()，这4个方法可能是分布在不同的类中的。这个例子和存储session有些像。

 *
 */
public class MethodShare_Demo {

  public static void main(String[] args) {
    User user = new User("jack");
    new Service1().service1(user);
  }

}

class Service1 {

  public void service1(User user) {
    //给ThreadLocal赋值，后续的服务直接通过ThreadLocal获取就行了。
    UserContextHolder.holder.set(user);
    new Service2().service2();
  }
}

class Service2 {

  public void service2() {
    User user = UserContextHolder.holder.get();
    System.out.println("service2拿到的用户:" + user.name);
    new Service3().service3();
  }
}

class Service3 {

  public void service3() {
    User user = UserContextHolder.holder.get();
    System.out.println("service3拿到的用户:" + user.name);
    //在整个流程执行完毕后，一定要执行remove
    UserContextHolder.holder.remove();
  }
}

class UserContextHolder {

  //创建ThreadLocal保存User对象
  public static ThreadLocal<User> holder = new ThreadLocal<>();
}

class User {

  String name;

  public User(String name) {
    this.name = name;
  }
}

//执行的结果：
//
//    service2拿到的用户:jack
//    service3拿到的用户:jack
//    场景四、Spring使用ThreadLocal解决线程安全问题


